/**
  ******************************************************************************
  * @file    Smartcard/src/smartcard.c
  * @author  MCD Application Team
  * @version V3.1.0
  * @date    07/27/2009
  * @brief   This file provides all the Smartcard firmware functions.
  ******************************************************************************
  * @copy
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2009 STMicroelectronics</center></h2>
  */

/** @addtogroup Smartcard
  * @{
  */

/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stddef.h>
#include "peripheral.h"
#include "clock_countor.h"
#include "etu_timer.h"
#include "error_code.h"
#include "base.h"

#include "stm32_smart_card.h"
#include "slot.h"


#define TRANSFER_OUT	0
#define TRANSFER_IN	1


#define HardwareModule_SourceFrequency		36000000


/*
	USART Parity-Select-Bit address Caculate. See DataSheet V10.1 section2.3.2
*/
//#define USART_CR1_Byte_Offset(usart) ((uint32_t)(usart) + offsetof(USART_TypeDef, CR1))
#define USART_CR1_Byte_Offset(usart_base) ((offsetof(USART_TypeDef, CR1)) + (uint32_t)(usart_base) - PERIPH_BASE)
#define USART_Parity_Bit_Num (9)
#define Bit_Word_Addr(Bit_Band_Base, Byte_Offset, Bit_Num) (uint32_t *)((Bit_Band_Base) \
	+ (Byte_Offset) * 32 + (Bit_Num) * 4)
#define USART_Parity_Select_Bit_Addr(usart_base) \
	Bit_Word_Addr(PERIPH_BB_BASE, USART_CR1_Byte_Offset(usart_base), USART_Parity_Bit_Num)
/* Private macro -------------------------------------------------------------*/
//	#define get_state(hw) ((hw)->usart->SR)
//#define flush_receive_buffer(hw) do{ volatile uint16_t dummy = USART_ReceiveData((hw)->usart);}while(0)
//	#define flush_receive_buffer(hw) USART_ReceiveData((hw)->usart)

/*Private function-----------------------------------------------------------*/
static void USART_SetDivider(uint32_t USARTx, uint32_t F, uint32_t D );

/* Private variables ---------------------------------------------------------*/


/* Global variables definition and initialization ----------------------------*/


hardware_module_t SmartCardUsarts[1] = {
	[0] = {
	    USART0, //usart
//		    USART_Parity_Select_Bit_Addr(USART2),
		0,
	    DIRECT_BYTE,//byte_direction
	    TRANSFER_IN,	//transfer_direction
	    USART_FLAG_TC,	//send_complete_flag
	    8				//uint32_t frequency_fraction
	},
#if 0
	[1] = {
	    USART1, //usart
	    USART_Parity_Select_Bit_Addr(USART1),
	    DIRECT_BYTE,//byte_direction
	    TRANSFER_IN,	//transfer_direction
	    USART_FLAG_TC,	//send_complete_flag
	    8				//uint32_t frequency_fraction
	},
#endif 
};


static void HardwareModule_RCC_Enable(void)
{
	rcu_periph_clock_enable(RCU_USART0);
}

static void SC_USART_Init(uint32_t com)
{
    /* USART configure */
    usart_deinit(com);

	usart_synchronous_clock_config(com, USART_CLEN_EN, USART_CPH_1CK, USART_CPL_LOW);
	usart_synchronous_clock_enable(com);
	
    usart_guard_time_config(com, 1);
	usart_prescaler_config(com, 4);
	
    usart_baudrate_set(com, 9677);
    usart_word_length_set(com, USART_WL_9BIT);
    usart_stop_bit_set(com, USART_STB_1_5BIT);
    usart_parity_config(com, USART_PM_EVEN);
    usart_hardware_flow_rts_config(com, USART_RTS_DISABLE);
    usart_hardware_flow_cts_config(com, USART_CTS_DISABLE);
    usart_receive_config(com, USART_RECEIVE_ENABLE);
    usart_transmit_config(com, USART_TRANSMIT_ENABLE);

    usart_enable(com);	
	usart_smartcard_mode_enable(com);
	usart_smartcard_mode_nack_disable(com);
}

void HardwareModule_Reset(hardware_module_t *hw)
{
	hw->transfer_direction = TRANSFER_OUT;
//		HardwareModule_Init();
}

void HardwareModule_Init(void)
{
	uint8_t i;

    /* Enable USART clock */
    HardwareModule_RCC_Enable();
    for(i = 0; i < sizeof(SmartCardUsarts) / sizeof(SmartCardUsarts[0]); i++){
		SC_USART_Init(SmartCardUsarts[i].usart);
    }
}

static void USART_SetDivider(uint32_t USARTx, uint32_t F, uint32_t D)
{
    uint32_t remainder;
    uint32_t integerdivider;
    uint32_t fractionaldivider;

    /* Integer part computing in case Oversampling mode is 16 Samples */
    integerdivider = F / D;
    //Fraction = remainder /D = DIV_Fraction / 16 => DIV_Fraction = remainder *16/D
    remainder = F % D;
    fractionaldivider = (remainder * (16 / 2)) / D;
    //fractionaldivider = (remainder * 16) / D;
    USART_BAUD(USARTx) = ((USART_BAUD_FRADIV | USART_BAUD_INTDIV) & (integerdivider << 4 | (fractionaldivider & 0x0F)));
//	    USARTx->BRR = (uint16_t)(integerdivider << 4 | fractionaldivider & 0x0F);
}


static void USART_SetStopbits(uint32_t USARTx, uint16_t stopbits_mark)
{
	usart_stop_bit_set(USARTx, stopbits_mark);
#if 0
#define CR2_STOP_CLEAR_Mask       ((uint16_t)0xCFFF)  /*!< USART CR2 STOP Bits Mask */

    uint32_t tmpreg;

    tmpreg = USARTx->CR2;
    /* Clear STOP[13:12] bits */
    tmpreg &= CR2_STOP_CLEAR_Mask;
    /* Configure the USART Stop Bits, Clock, CPOL, CPHA and LastBit ------------*/
    /* Set STOP[13:12] bits according to USART_StopBits value */
    //tmpreg |= (uint32_t)USART_InitStruct->USART_StopBits;
    tmpreg |= stopbits_mark;
    /* Write to USART CR2 */
    USARTx->CR2 = (uint16_t)tmpreg;
#endif 
}


void HardwareModule_ClockEnable(hardware_module_t *hw)
{
	usart_synchronous_clock_enable(hw->usart);
#if 0
    USART_ClockInitTypeDef USART_ClockInitStructure;
    USART_TypeDef *usart = hw->usart;

    USART_ClockInitStructure.USART_Clock = USART_Clock_Enable;
    USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;
    USART_ClockInitStructure.USART_CPHA = USART_CPHA_1Edge;
    USART_ClockInitStructure.USART_LastBit = USART_LastBit_Enable;
    USART_ClockInit(usart, &USART_ClockInitStructure);
#endif 
}

void HardwareModule_ClockDisable(hardware_module_t *hw)
{
	usart_synchronous_clock_disable(hw->usart);

#if 0
    USART_ClockInitTypeDef USART_ClockInitStructure;
    USART_TypeDef *usart = hw->usart;

    USART_ClockInitStructure.USART_Clock = USART_Clock_Disable;
    USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;
    USART_ClockInitStructure.USART_CPHA = USART_CPHA_1Edge;
    USART_ClockInitStructure.USART_LastBit = USART_LastBit_Enable;
    USART_ClockInit(usart, &USART_ClockInitStructure);
#endif 
}

void HardwareModule_SetStopbits(hardware_module_t *hw, uint8_t stopbits)
{
    uint16_t stopbits_mark = stopbits == 1 ? USART_STB_0_5BIT : USART_STB_1_5BIT;
#if 0
    USART_TypeDef *USARTx = hw->usart;

    if(stopbits == 1)
    {
        stopbits_mark = USART_StopBits_0_5;
    }
    else
    {
        stopbits_mark = USART_StopBits_1_5;
    }
#endif 
	usart_stop_bit_set(hw->usart, stopbits_mark);

//	    USART_SetStopbits(USARTx, stopbits_mark);
}

void HardwareModule_NAKEnable(hardware_module_t *hw)
{
	usart_smartcard_mode_nack_enable(hw->usart);
//	    USART_SmartCardNACKCmd(hw->usart, ENABLE);
}

void HardwareModule_NAKDisable(hardware_module_t *hw)
{
	usart_smartcard_mode_nack_disable(hw->usart);

//	    USART_SmartCardNACKCmd(hw->usart, DISABLE);
}
extern uint32_t etu_to_clock(uint32_t etu, uint8_t FiDi);
void HardwareModule_SoftwareNak(uint8_t FiDi)
{
#if 0
    uint32_t clock;
    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Pin = SC_USART_PIN_TX;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(SC_USART_GPIO, &GPIO_InitStructure);

    GPIO_SetBits(SC_USART_GPIO, SC_USART_PIN_TX);
    clock = etu_to_clock(1, FiDi);
    ClockCountor_Wait(clock / 2); //stop bit
    GPIO_ResetBits(SC_USART_GPIO, SC_USART_PIN_TX);
    ClockCountor_Wait(clock + clock / 2); //low duration

    GPIO_InitStructure.GPIO_Pin = SC_USART_PIN_TX;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(SC_USART_GPIO, &GPIO_InitStructure);
    USART_ReceiveData(SC_USART);
#endif 
}


static inline void HardwareModule_SetParityOdd(hardware_module_t *hw)
{
//	    *hw->parity_odd = 1;
}

static inline void HardwareModule_SetParityEven(hardware_module_t *hw)
{
//	    *hw->parity_odd = 0;
}

void HardwareModule_SetByteDirection(hardware_module_t *hw, uint8_t dir)
{
    if(dir != DIRECT_BYTE)
    {
        HardwareModule_SetParityOdd(hw);
    }
    else
    {
        HardwareModule_SetParityEven(hw);
    }

    hw->byte_direction = dir;
}

uint8_t HardwareModule_GetByteDirection(hardware_module_t *hw)
{
    return hw->byte_direction;
}

void HardwareModule_SetETU(hardware_module_t *hw, uint8_t FiDi)
{
    uint32_t F;
    uint32_t D;
    uint32_t frequency_fraction = hw->frequency_fraction;

    F = convert_fi_code_to_value(FiDi >> 4);
    D = convert_di_code_to_value(FiDi & 0x0F);
    F = F * frequency_fraction / 16;
    USART_SetDivider(hw->usart, F, D);
}

static uint32_t Usart_GetFrequency(uint32_t usart)
{
	if(usart == USART0)
	{
		return rcu_clock_freq_get(CK_APB2);
	}
	return rcu_clock_freq_get(CK_APB1);
}

void HardwareModule_SetFrequency(hardware_module_t *hw, uint32_t frequency)
{
    uint32_t usart = hw->usart;
    uint32_t usart_freq = Usart_GetFrequency(usart);
    uint32_t div = usart_freq / frequency;
    
    hw->frequency_fraction = div;
	usart_prescaler_config(usart, div / 2);
//	    USART_SetPrescaler(usart, div / 2);
    //ETUTimer_Init(frequency);
}

void HardwareModule_SetGuardTime(hardware_module_t *hw, uint8_t guard_time)
{
	usart_guard_time_config(hw->usart, guard_time);
//	    USART_SetGuardTime(hw->usart, guard_time);
}

void HardwareModule_SetCharDuration(hardware_module_t *hw, uint8_t char_duration)
{
    if(char_duration == 11)
    {
        hw->send_complete_flag = USART_FLAG_TBE;
    }
    else
    {
        hw->send_complete_flag = USART_FLAG_TC;
    }
}
/*
static uint16_t get_state(hardware_module_t *hw)
{
	return hw->usart->SR;
}
*/


#define direct_send_byte(hw, byte) 	usart_data_transmit((hw)->usart, byte)
#define reverse_send_byte(hw, byte) usart_data_transmit((hw)->usart, reverse_byte(~(byte)))

//	#define send_data(hw, data) do{ \
//		if(hw->byte_direction != DIRECT_BYTE) reverse_send_byte(hw, data);\
//		else 			   direct_send_byte(hw, data); \
//	}while(0)

//	#define get_send_error_mark(hw) (hw->error_mark & (~(USART_FLAG_PE | USART_FLAG_NE | USART_FLAG_ORE )))
//	#define is_send_error(sr) ((sr) & USART_FLAG_FE)
//	#define clear_send_error(hw) do{USART_GetFlagStatus((hw)->usart, USART_FLAG_FE); USART_ReceiveData((hw)->usart);}while(0)
#define is_send_complete(sr, complete_flag) ((sr) & (complete_flag))

static uint32_t get_state(hardware_module_t* hw){
	return USART_STAT(hw->usart);
}

static uint16_t flush_receive_buffer(hardware_module_t* hw){
	return usart_data_receive(hw->usart);
}

static void send_data(hardware_module_t* hw, uint16_t data){
	uint16_t byte;
	
	byte = (hw->byte_direction != DIRECT_BYTE) ? data : reverse_byte(~data);	
	usart_data_transmit(hw->usart, byte);
}

static void clear_send_error(hardware_module_t *hw){
	uint32_t usart = hw->usart;
	usart_flag_get(usart, USART_FLAG_FERR);
	usart_data_receive(usart);
}

uint8_t HardwareModule_CheckNAK(hardware_module_t *hw)
{
    uint32_t i;
    uint8_t err = NO_ERR;
	uint32_t usart = hw->usart;
	
    for(i = 0; i < 30; i++)    {
		if(usart_flag_get(usart, USART_FLAG_FERR)){
			usart_data_receive(usart);
			err = ERR_SEND;
			break;
		}
    }

    return err;
}

#if 0
uint8_t HardwareModule_SendByte(hardware_module_t *hw, uint8_t byte)
{
    uint16_t sr;
    uint8_t err = NO_ERR;
    uint16_t complete_flag = hw->send_complete_flag;

    hw->transfer_direction = TRANSFER_OUT;
    clear_send_error(hw);

    do
    {
        sr = get_state(hw);
    }
    while(!is_send_complete(sr, complete_flag));

    send_data(hw, byte);

    do
    {
        sr = get_state(hw);
    }
    while(!is_send_complete(sr, complete_flag));

    return err;
}
#endif 

uint8_t HardwareModule_SendByte(hardware_module_t *hw, uint8_t byte)
{
    uint8_t err = NO_ERR;
	uint32_t usart = hw->usart;
	
    hw->transfer_direction = TRANSFER_OUT;
    clear_send_error(hw);
	
	while(RESET == usart_flag_get(usart, USART_FLAG_TBE)){}
	usart_data_transmit(usart, byte);
	while(RESET == usart_flag_get(usart, USART_FLAG_TC)){}

    return err;
}


uint16_t HardwareModule_Flush(hardware_module_t *hw)
{
    return flush_receive_buffer(hw);
}

static uint16_t reverse_receive_byte(hardware_module_t *hw)
{
    uint16_t data = USART_DATA(hw->usart);
    uint16_t parity_bit;

    data = ~data;
    parity_bit = data & 0x0100;

    return (uint16_t)reverse_byte((uint8_t)data) | parity_bit;
}

//#define reverse_receive_byte(hw) (~(reverse_byte(USART_ReceiveData((hw)->usart))))
//	#define direct_receive_byte(hw) USART_ReceiveData((hw)->usart)
//	#define receive_data(hw) (((hw)->byte_direction != DIRECT_BYTE) \
//		?  reverse_receive_byte(hw)\
//		: direct_receive_byte(hw))

#define is_parity_error(sr) ((sr) & USART_FLAG_PERR)
#define is_receive_compelet(sr) ((sr) & USART_FLAG_RBNE)
#define get_receive_error_mark(hw) ((hw)->error_mark & (~USART_FLAG_FERR))


static uint16_t receive_data(hardware_module_t *hw){
	return ((hw)->byte_direction != DIRECT_BYTE) 
		?  reverse_receive_byte(hw)
		: USART_DATA(hw->usart);
}

uint8_t HardwareModule_ReceiveByte(hardware_module_t *hw, uint16_t *byte)
{

    uint8_t err = NO_ERR;

    if(hw->transfer_direction == TRANSFER_OUT){
        hw->transfer_direction = TRANSFER_IN;
        flush_receive_buffer(hw);
    }

	while(1){
		if(ETUTimer_CheckTimeout()) {
			return ERR_TIMEOUT;
		}

		if(!Slot_CheckCard(hw->number)){
			return ERR_CARD_ABSENT;
		}

		if(SET == usart_flag_get(hw->usart, USART_FLAG_RBNE)){
			break;
		}
	}

    if(SET == usart_flag_get(hw->usart, USART_FLAG_PERR)) {
        err = ERR_PARITY;
    }

    *byte = receive_data(hw);
    return err;
}


#if 0
uint8_t HardwareModule_ReceiveByte(hardware_module_t *hw, uint16_t *byte)
{

    uint8_t err = NO_ERR;
    uint32_t sr;

    if(hw->transfer_direction == TRANSFER_OUT)
    {
        hw->transfer_direction = TRANSFER_IN;
        flush_receive_buffer(hw);
    }

    do
    {
        if(ETUTimer_CheckTimeout())
        {
            return ERR_TIMEOUT;
        }

        if(!Slot_CheckCard(hw->number))
        {
            return ERR_CARD_ABSENT;
        }
        sr = get_state(hw);
    }
    while(!is_receive_compelet(sr));

    if(is_parity_error(sr))
    {
        err = ERR_PARITY;
    }

    *byte = receive_data(hw);
    return err;
}
#endif 

#if 1

void test_HardwareModule(void)
{
	static uint16_t rx = 0;
	static uint8_t tx = 0xC0;
    volatile uint32_t i;
	
    HardwareModule_Init();
    HardwareModule_SetGuardTime(&SmartCardUsarts[0], 0);

    while(1)
    {
        //
        HardwareModule_SendByte(&SmartCardUsarts[0], tx);
        HardwareModule_SendByte(&SmartCardUsarts[0], tx);

        for(i = 0; i < 0xFFFF; i++)
        {}

		HardwareModule_SetGuardTime(&SmartCardUsarts[0], 1);
		HardwareModule_SendByte(&SmartCardUsarts[0], 0x55);
		HardwareModule_SendByte(&SmartCardUsarts[0], 0x55);
		HardwareModule_ReceiveByte(&SmartCardUsarts[0], &rx);
		for(i = 0; i < 0xFFFF; i++)
		{}
    }
}
#endif

